package util

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
)

// pkcs7Padding 填充
func pkcs7Padding(data []byte, blockSize int) []byte {
	//判断缺少几位长度。最少1，最多 blockSize
	padding := blockSize - len(data)%blockSize
	//补足位数。把切片[]byte{byte(padding)}复制padding个
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// pkcs7UnPadding 填充的反向操作
func pkcs7UnPadding(data []byte) (r []byte, err error) {

	length := len(data)
	if length == 0 {
		return nil, errors.New("加密字符串错误！")
	}
	//获取填充的个数
	unPadding := int(data[length-1])
	l := length - unPadding
	if l < 0 || l > length {
		return r, errors.New("数据错误")
	}
	r = data[:l]
	return r, nil
}

// 校验key是否满足32
func checkKey(key []byte, keyLen int) []byte {

	keys := string(key)
	if len(keys) == keyLen {
		return key
	} else if len(keys) > keyLen {
		keys = keys[0:keyLen]
	} else {
		max := keyLen - len(keys)
		for i := 0; i < max; i++ {
			keys += "1"
		}
	}
	return []byte(keys)
}

// 加密 AesEncrypt ,CBC模式 ,data:加密前的数据， key:秘钥,keyLen:加密长度,一般是16,32,48,56,64等
func AesEncrypt(data []byte, key []byte, keyLen int) ([]byte, error) {
	key = checkKey(key, keyLen)
	//创建加密实例
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	//判断加密快的大小
	blockSize := block.BlockSize()
	//填充
	encryptBytes := pkcs7Padding(data, blockSize)
	//初始化加密数据接收切片
	crypted := make([]byte, len(encryptBytes))
	if len(key) < blockSize {
		return nil, errors.New("key长度错误")
	}
	//使用cbc加密模式
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
	//执行加密
	blockMode.CryptBlocks(crypted, encryptBytes)
	return crypted, nil
}

// 解密 AesDecrypt   CBC模式  data:加密的数据， key:秘钥,keyLen:加密长度,一般是16,32,48,56,64等
func AesDecrypt(data []byte, key []byte, keyLen int) ([]byte, error) {
	key = checkKey(key, keyLen)
	//创建实例
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	//获取块的大小
	blockSize := block.BlockSize()
	if len(key) < blockSize {
		return nil, errors.New("key长度错误")
	}

	//使用cbc
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
	//初始化解密数据接收切片
	crypted := make([]byte, len(data))
	//执行解密
	blockMode.CryptBlocks(crypted, data)
	//去除填充
	crypted, err = pkcs7UnPadding(crypted)
	if err != nil {
		return nil, err
	}
	return crypted, nil
}

// EncryptByAes Aes加密 后 base64
func AesEncryptBase64(data []byte, key []byte, keyLen int) (string, error) {
	res, err := AesEncrypt(data, key, keyLen)
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(res), nil
}

// DecryptByAes base64解码后 Aes 解密
func AesDecryptBase64(data string, key []byte, keyLen int) ([]byte, error) {
	dataByte, err := base64.URLEncoding.DecodeString(data)
	if err != nil {
		return nil, err
	}
	return AesDecrypt(dataByte, key, keyLen)
}
